package sheep.utils.fileio;

import edu.uci.ics.jung.visualization.PersistentLayout.Point;
import java.awt.Color;
import java.awt.geom.Point2D;
import java.util.logging.Level;
import java.util.logging.Logger;
import sheep.controller.Workspace;
import java.io.*;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import org.jdom.*;
import org.jdom.input.SAXBuilder;
import org.jdom.output.*;
import sheep.model.Calendrier;
import sheep.model.Note;
import sheep.model.Project;
import sheep.model.Task;
import sheep.model.Task.TaskMode;
import sheep.model.Task.TaskState;
import sheep.model.WorkGroup;
import sheep.model.Worker;
import sheep.model.graph.Graph;
import sheep.model.graph.OurVertex;
import sheep.view.Component.CalendarCellRenderer.Adapter;

public class WorkspaceLoader {
  private Workspace workSpace = new Workspace();
  private String fileName;
  private Document document;
  private Element root;
  private LinkedList<Task> addedTasks2 = new LinkedList<Task>();
  LinkedList<Task> addedTasks = new LinkedList<Task>();
  private LinkedList<Task> addedTasks3 = new LinkedList<Task>();
  
  
  public WorkspaceLoader(Workspace w, String fileName) {
    try {
      SAXBuilder sxb = new SAXBuilder();

      this.workSpace = w;
      this.fileName = fileName;
      document = sxb.build(new File(this.fileName));
      root = document.getRootElement();
      
    } catch (JDOMException ex) {
      Logger.getLogger(WorkspaceLoader.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
      Logger.getLogger(WorkspaceLoader.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
  
  private Project loadProject(Element project){
    int id = Integer.valueOf(project.getChild("id").getText());
    String name = project.getChild("name").getText();
    String comment = project.getChild("comment").getText();
    Boolean detailed = Boolean.valueOf(project.getChild("detailed").getText());

    Point2D location = new Point2D.Double(Double.valueOf(project.getChild("location").getChild("xpos").getText()),
                                 Double.valueOf(project.getChild("location").getChild("ypos").getText()));
    int duration = Integer.valueOf(project.getChild("duration").getText());

    Calendar actualBeginTime = Calendar.getInstance();
    actualBeginTime.setTimeInMillis(Long.valueOf(project.getChild("actualbegintime").getText()));
    Calendar actualEndTime = Calendar.getInstance();
    actualEndTime.setTimeInMillis(Long.valueOf(project.getChild("actualendtime").getText()));

    Calendar earliestBeginTime = Calendar.getInstance();
    earliestBeginTime.setTimeInMillis(Long.valueOf(project.getChild("earliestbegintime").getText()));
    Calendar earliestEndTime = Calendar.getInstance();
    earliestEndTime.setTimeInMillis(Long.valueOf(project.getChild("earliestendtime").getText()));

    Calendar latestBeginTime = Calendar.getInstance();
    latestBeginTime.setTimeInMillis(Long.valueOf(project.getChild("latestbegintime").getText()));
    Calendar latestEndTime = Calendar.getInstance();
    latestEndTime.setTimeInMillis(Long.valueOf(project.getChild("latestendtime").getText()));

    TaskState state = TaskState.valueOf(project.getChild("state").getText());
    TaskMode mode = TaskMode.valueOf(project.getChild("mode").getText());

    // On fixe les attributs
    Project newProject = new Project(name,this.workSpace);
    newProject.addGraph(null);
    workSpace.setCurrentProject(newProject);
    workSpace.setCurrentTask(newProject);
    
    newProject.setID(id);
    newProject.setDetailled(detailed);
    newProject.setDuration(duration, false);
    newProject.setComment(comment);
    newProject.setLocation(location);
    newProject.setActualBeginTime(actualBeginTime, false);
    newProject.setActualEndTime(actualEndTime, false);
    newProject.setEarliestBeginTime(earliestBeginTime,false);
    newProject.setEarliestEndTime(earliestEndTime);
    newProject.setLatestBeginTime(latestBeginTime,false);
    newProject.setLatestEndTime(latestEndTime);
    newProject.setState(state);
    newProject.setMode(mode);

    /* On ajoute les workers */
    Element workers = project.getChild("workers");
    for(Object w : workers.getChildren("worker")) {
      Element currentWorker = (Element)w;
      int IdWorker = Integer.valueOf(currentWorker.getText());
      newProject.getWorkersList().add(this.workSpace.getWorkerFromId(IdWorker));
    }

    /* On ajoute les managers */
    Element managers = project.getChild("managers");
    for(Object m : managers.getChildren("manager")) {
      Element currentManager = (Element)m;
      int IdManager = Integer.valueOf(currentManager.getText());
      newProject.getManagers().add(this.workSpace.getWorkerFromId(IdManager));
    }
      
      //ajout des enfants
//    for(Object c : project.getChild("children").getChildren("child")){
//      Task child = loadTask((Element)c);
//      newProject.getGraph().addVertex(child,child.getLocation());
//      System.out.println(child);
//    }
      
    return newProject;
  }
  
  private Task loadTask(Element task, Task mother){
    int id = Integer.valueOf(task.getChild("id").getText());
    String name = task.getChild("name").getText();
    String comment = task.getChild("comment").getText();
    Boolean detailed = Boolean.valueOf(task.getChild("detailed").getText());

    Point2D location = new Point2D.Double(Double.valueOf(task.getChild("location").getChild("xpos").getText()),
                                 Double.valueOf(task.getChild("location").getChild("ypos").getText()));
    int duration = Integer.valueOf(task.getChild("duration").getText());

    Calendar actualBeginTime = Calendar.getInstance();
    actualBeginTime.setTimeInMillis(Long.valueOf(task.getChild("actualbegintime").getText()));
    Calendar actualEndTime = Calendar.getInstance();
    actualEndTime.setTimeInMillis(Long.valueOf(task.getChild("actualendtime").getText()));

    Calendar earliestBeginTime = Calendar.getInstance();
    earliestBeginTime.setTimeInMillis(Long.valueOf(task.getChild("earliestbegintime").getText()));
    Calendar earliestEndTime = Calendar.getInstance();
    earliestEndTime.setTimeInMillis(Long.valueOf(task.getChild("earliestendtime").getText()));

    Calendar latestBeginTime = Calendar.getInstance();
    latestBeginTime.setTimeInMillis(Long.valueOf(task.getChild("latestbegintime").getText()));
    Calendar latestEndTime = Calendar.getInstance();
    latestEndTime.setTimeInMillis(Long.valueOf(task.getChild("latestendtime").getText()));

    TaskState state = TaskState.valueOf(task.getChild("state").getText());
    TaskMode mode = TaskMode.valueOf(task.getChild("mode").getText());

    // On fixe les attributs
    Task newTask = new Task(name, duration, detailed, workSpace);
    newTask.addGraph(mother);
    newTask.setID(id);
    //newProject.setDetailled(detailed);
    //newProject.setDuration(duration);
    newTask.setComment(comment);
    newTask.setLocation(mother.getGraph().getVv().transform(location));
    mother.getGraph().getVertexLocations().setLocation(
            mother.getGraph().getVertex(newTask),mother.getGraph().getVv().transform(location));
    newTask.setActualBeginTime(actualBeginTime, false);
    newTask.setActualEndTime(actualEndTime, false);
    newTask.setEarliestBeginTime(earliestBeginTime,false);
    newTask.setEarliestEndTime(earliestEndTime);
    newTask.setLatestBeginTime(latestBeginTime,false);
    newTask.setLatestEndTime(latestEndTime);
    newTask.setState(state);
    newTask.setMode(mode);
    
    //ajout des enfants
    for(Object c : task.getChild("children").getChildren("task")){
      Task child = loadTask((Element)c,newTask);
      newTask.getGraph().addVertex(child,child.getLocation());
    }
    
    return newTask;
  }
  
  
  private Worker loadWorker(Element worker){
    int id = Integer.valueOf(worker.getChild("id").getText());
      String firstname = worker.getChild("firstname").getText();
      String lastname = worker.getChild("lastname").getText();
      String job = worker.getChild("job").getText();
      String picture = worker.getChild("picture").getText();
      Calendar birthDate = Calendar.getInstance();
      birthDate.setTimeInMillis(Long.valueOf(worker.getChild("birthdate").getText()));
      String address = worker.getChild("address").getChild("street").getText();
      String city = worker.getChild("address").getChild("city").getText();
      String postCode = worker.getChild("address").getChild("postalcode").getText();
      
      Worker newWorker = new Worker(firstname, lastname, birthDate, address, postCode, city, picture, job);
      newWorker.setId(id);
      
      return newWorker;
  }
  
  private WorkGroup loadGroup(Element group){
      int id = Integer.valueOf(group.getChild("id").getText());
      String name = group.getChild("name").getText();
      String picture = group.getChild("picture").getText();
      
      WorkGroup newGroup = new WorkGroup(name, picture);
      newGroup.setId(id);
      return newGroup;
  }
  
  private Calendrier loadCalendrier(Element calendar){
    int id = Integer.valueOf(calendar.getChild("id").getText());
    String name = calendar.getChild("name").getText();
    String message = calendar.getChild("message").getText();
    String iconurl = calendar.getChild("iconurl").getText();

    Element color = calendar.getChild("color");
    int red = Integer.valueOf(color.getChild("red").getText());
    int green = Integer.valueOf(color.getChild("green").getText());
    int blue = Integer.valueOf(color.getChild("blue").getText());
    Color c = new Color(red, green, blue);

    boolean displayed = Boolean.valueOf(calendar.getChild("displayed").getText());

    Calendrier newCalendar = new Calendrier(name, Adapter.Status.NOT_SELECTED, message, iconurl, c);
    newCalendar.setId(id);
    newCalendar.setIsDisplay(displayed);

    return newCalendar;
  }
  
  private Note loadNote(Element note){
    int id = Integer.valueOf(note.getChild("id").getText());
      
    Calendar startDate = Calendar.getInstance();
    startDate.setTimeInMillis(Long.valueOf(note.getChild("startdate").getText()));
    Calendar endDate = Calendar.getInstance();
    endDate.setTimeInMillis(Long.valueOf(note.getChild("enddate").getText()));

    String title = note.getChild("title").getText();
    String location = note.getChild("location").getText();
    String comment = note.getChild("comment").getText();

    //Calendrier c = workSpace.getCalendrierFromId(Integer.valueOf(note.getChild("calendar").getText()));

    // Création de la note & ajout au workspace
    Note newNote = new Note();
    newNote.setId(id);
    newNote.setTitle(title);
    newNote.setLocation(location);
    newNote.setComment(comment);
    newNote.setDate(startDate);
    newNote.setEndDate(endDate);

    return newNote;
  }
  
  
  public void loadWorkspace() {
    
    // On charge les personnes
    Element workers = root.getChild("workers");
    List workersList = workers.getChildren("worker");
    workSpace.getWorkersList().clear();
    for(Object w : workersList) {
      Element currentWorker = (Element)w;
      workSpace.getWorkersList().add(loadWorker(currentWorker));
    }
    
    // On charge les groupes
    Element workgroups = root.getChild("workgroups");
    List workgroupsList = workgroups.getChildren("workgroup");
    workSpace.getWorkGroupsList().clear();
    for(Object g : workgroupsList) {
      Element currentGroup = (Element)g;
      WorkGroup workgroup = loadGroup(currentGroup);
      workSpace.getWorkGroupsList().add(workgroup);
      
      // On ajoute les membres du groupe
      Element members = currentGroup.getChild("members");
      List membersList = members.getChildren("member");
      workgroup.getWorkersList().clear();
      for(Object w : membersList) {
        Element currentWorker = (Element)w;
        Worker worker = workSpace.getWorkerFromId(Integer.valueOf(currentWorker.getText()));
        workgroup.addWorker(worker);
      }
    }
    
    // On charge les calendriers
    Element calendriers = root.getChild("calendars");
    List calendriersList = calendriers.getChildren("calendar");
    workSpace.getCalendarList().clear();
    workSpace.getNoteList().clear();
    
    for(Object c : calendriersList) {
      Element currentCalendrier = (Element)c;
      Calendrier calendrier = loadCalendrier(currentCalendrier);
      workSpace.getCalendarList().add(calendrier);
      
      // On charge les notes
      List notesList = currentCalendrier.getChild("notes").getChildren("note");
      for(Object n : notesList){
        Note note = loadNote((Element)n);
        System.out.println(note.getTitle());
        calendrier.addNote(note);
        note.setCalendrier(calendrier);
        workSpace.getNoteList().add(note);
      }
    }
    
    // On charge les projets
    addedTasks = new LinkedList<Task>();
    LinkedList<Element> addedElement = new LinkedList<Element>();
    
    //LinkedList<Task> tasks = new LinkedList<Task>();
    
    Element projects = root.getChild("projects");
    List projectsList = projects.getChildren("task");
    workSpace.getProjectList().clear();
    for(Object p : projectsList) 
    {
      Element project = (Element)p;
      Project newProject = loadProject(project);
      System.out.println(newProject);
      workSpace.getProjectList().add(newProject);
      
      // children
      for(Object c : project.getChild("children").getChildren("task")){
        Task child = loadTask((Element)c,newProject);
        newProject.getGraph().addVertex(child,child.getLocation());
        System.out.println(child);
        addedTasks.add(child);
        addedElement.add((Element)c);
      }
      
      // edges
      for(Element c : addedElement){
        Task t1, t2;
        int id1 = Integer.valueOf(c.getChild("id").getText());
        System.out.println(id1);
        OurVertex v1 = newProject.getGraph().getVertex(id1);
        if(v1 != null){
          t1 = v1.getTask();
          if(t1 != null){
            for(Object i : c.getChild("predecessors").getChildren("id")){
              int id2 = Integer.valueOf(((Element)i).getText());
              OurVertex v2 = newProject.getGraph().getVertex(id2);
              if(v2 != null){
                t2 = newProject.getGraph().getVertex(id2).getTask();
                if(t2 != null)
                  newProject.getGraph().addEdge(t2, t1);
              }
            }
          }
        }
      }
    }
    
    for(Object c : workSpace.getCalendarList()){
      Calendrier cal = (Calendrier)c;
      System.out.println(cal.getName());
      for(Object n : cal.getNoteList())
        System.out.println(((Note)n).getTitle());
    }
    
    
    for(Task t : workSpace.getProjectList()) {  
      System.out.println("Project loaded: " + t.getName());
    }
    
    workSpace.setSavePath(new File(this.fileName).getPath());
    workSpace.setSaveFile(new File(this.fileName).getName());
  }
  
  
  public Task getAdded(int id) {
    for(Task t : addedTasks3) {
      if(t.getID()==id)
        return t;
    }
    
    return null;
  }
  
  public LinkedList<Task> getFromParent(int id) {
    LinkedList<Task> lst = new LinkedList<Task>();
    
    for(Task t : addedTasks) {
      if(t.getSuperTask()!=null && t.getSuperTask().getID() == id)
        lst.add(t);
    }
    
    return lst;
  }
  
}